#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <memory>
#include <unistd.h>
#include <string>
#include <functional>
#include "Log.hpp"
#include "Comm.hpp"
#include "InetAddr.hpp"
using namespace LogModule;
class Socket
{
public:
    virtual void SocketOrDie() = 0;
    virtual bool BindOrDie() = 0;
    virtual bool ListenOrDie() = 0;
    virtual int Accept(InetAddr* client) = 0;
    virtual bool Close() = 0;
    virtual void SetSockOpt() = 0;
    virtual int Send(std::string& message) = 0;
    virtual int Recv(std::string* message) = 0;
    virtual int Fd() = 0;
    //virtual ~Socket();
    void BuildTcpSocket()
    {
        SocketOrDie();
        BindOrDie();
        ListenOrDie();
    }
private:
};

class TcpSocket: public Socket
{
public:
    virtual int Fd()
    {
        return _sockfd;
    }
    TcpSocket(int port ):_sockfd(gdefaultsockfd),_port(port)
    {

    }
    TcpSocket(int sockfd,int port):_sockfd(sockfd),_port(port)
    {

    }
    ~TcpSocket()
    {
        Close();
    }
    virtual void SetSockOpt()
    {
        int reuse = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    }
    virtual void SocketOrDie()
    {
        _sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(_sockfd<0)
        {
            LOG(LogLevel::DEBUG)<<"socket error";
            exit(SOCKETERR);
        }
        SetSockOpt();
    }
    virtual bool BindOrDie()
    {
        if(_sockfd<0)
            return false;
        InetAddr local(_port);
        int n = bind(_sockfd,local.Addr(),local.In_Size());
        if(n<0)
        {
            LOG(LogLevel::DEBUG)<<"bind error";
            return false;
        }
        LOG(LogLevel::DEBUG)<<"bind success: port "<<_port;
        return true;
    }   
    virtual bool ListenOrDie()
    {
        if(_sockfd<0)
        {
            return false;
        }
        int n = listen(_sockfd,gbacklog);
        if(n<0)
        {
            LOG(LogLevel::DEBUG)<<"listen error";
            return false;
        }
        LOG(LogLevel::DEBUG)<<"listen success: "<<_sockfd;
        return true;
    }
    virtual int Accept(InetAddr* client)
    {
        if(client==nullptr)
            return -1;

        struct sockaddr_in peer;
        socklen_t peerlen = sizeof(peer);
        int newsockfd = accept(_sockfd,CONV(&peer),&peerlen);
        if(newsockfd<0)
        {
            //LOG(LogLevel::DEBUG)<<"accept error";
            return -1;
        }
        *client = InetAddr(peer);
        //Socket* ret = new TcpSocket(newsockfd,_port);
        return newsockfd;
    }
    virtual bool Close()
    {
        close(_sockfd);
        //LOG(LogLevel::DEBUG)<<"close sokfd: "<<_sockfd;
        return true;
    }
    virtual int Send(std::string& message)
    {
        int n = send(_sockfd,message.c_str(),message.size(),0);
        if(n>0)
        {
            //std::cout<<"send success"<<std::endl;
        }
        return n;
    }
    virtual int Recv(std::string* message)
    {
        char buffer[1024];
        //std::cout<<"接受请求"<<std::endl;
        int n = recv(_sockfd,buffer,sizeof(buffer)-1,0);
        if(n>0)
        {
            buffer[n] = 0;
            *message = buffer;
            //std::cout<<"accept message: "<<*message<<std::endl;
        }
        return n;
    }
private:
    int _port;
    int _sockfd;
};

